/* Copyright (C) 2005-2013, Unigine Corp. All rights reserved.
 *
 * File:    vertex_cloud_ambient.h
 * Desc:    Billboards cloud ambient shader
 * Version: 1.02
 * Author:  Alexander Zapryagaev <frustum@unigine.com>
 *
 * This file is part of the Unigine engine (http://unigine.com/).
 *
 * Your use and or redistribution of this software in source and / or
 * binary form, with or without modification, is subject to: (i) your
 * ongoing acceptance of and compliance with the terms and conditions of
 * the Unigine License Agreement; and (ii) your inclusion of this notice
 * in any version of this software that you use or redistribute.
 * A copy of the Unigine License Agreement is available by contacting
 * Unigine Corp. at http://unigine.com/
 */

/******************************************************************************\
*
* OpenGL
*
\******************************************************************************/

#ifdef OPENGL
	
	#ifndef VERTEX_CLOUD_AMBIENT
		#define VERTEX_CLOUD_AMBIENT
		
		uniform float4 cloud_0_color;
		uniform float4 cloud_1_color;
		uniform float cloud_01_scale;
		uniform float cloud_power;
		uniform float cloud_scattering;
		uniform float cloud_distance;
		
	#else
		
		gl_Position = getPosition(vertex);
		
		float3 direction = normalize(vertex.xyz - float3(row_0.w,row_1.w,row_2.w));
		float3 color = lerp(cloud_1_color.xyz,cloud_0_color.xyz,dot(direction,s_light_direction) * 0.5f + 0.5f) * cloud_01_scale;
		
		direction = vertex.xyz * s_depth_range.w;
		float distance = length(direction);
		
		s_texcoord_0.xy = texcoord.xy;
		
		s_texcoord_1.xyz = direction;
		
		float ray_density = s_scattering_ray_beta.w;
		float mie_density = s_scattering_mie_beta.w;
		
		float2 falloff = s_scattering_falloff.xy * (dot(direction,s_scattering_up_direction) + s_scattering_falloff.z);
		if(abs(falloff.x) > 0.01f) ray_density *= (1.0f - exp2(-falloff.x)) / falloff.x;
		if(abs(falloff.y) > 0.01f) mie_density *= (1.0f - exp2(-falloff.y)) / falloff.y;
		
		float scattering_distance = pow(distance,s_scattering_power);
		float3 scattering = exp2(-(s_scattering_ray_beta.xyz * ray_density + s_scattering_mie_beta.xyz * mie_density) * scattering_distance);
		
		float angle = dot(direction,s_scattering_light_direction) / distance;
		float ray_phase = 1.0f + angle * angle * s_scattering_ray_dash.w;
		float mie_greenstein = rsqrt(s_scattering_greenstein.y - s_scattering_greenstein.z * angle);
		float mie_phase = min(s_scattering_greenstein.x * mie_greenstein,s_scattering_mie_dash.w * scattering_distance);
		float3 inscattering = s_scattering_ray_dash.xyz * ray_phase + s_scattering_mie_dash.xyz * mie_phase;
		
		float fade = saturate(length(position) / max(width,height));
		
		s_texcoord_2.xyz = scattering * color;
		s_texcoord_2.w = saturate(dot(scattering,float3(cloud_scattering))) * saturate(-vertex.z / cloud_distance) * fade;
		s_texcoord_3.xyz = inscattering * (1.0f - scattering);
		s_texcoord_3.w = 0.0f;
		
	#endif
	
/******************************************************************************\
*
* Direct3D11
*
\******************************************************************************/

#elif DIRECT3D11
	
	#ifndef VERTEX_CLOUD_AMBIENT
		#define VERTEX_CLOUD_AMBIENT
		
		struct VERTEX_OUT {
			float4 position : SV_POSITION;
			float2 texcoord_0 : TEXCOORD0;
			float3 texcoord_1 : TEXCOORD1;
			float4 texcoord_2 : TEXCOORD2;
			float4 texcoord_3 : TEXCOORD3;
		};
		
		cbuffer shader_parameters {
			float4 cloud_0_color;
			float4 cloud_1_color;
			float cloud_01_scale;
			float cloud_power;
			float cloud_scattering;
			float cloud_distance;
		};
		
	#else
		
		OUT.position = getPosition(vertex);
		
		float3 direction = normalize(vertex.xyz - float3(row_0.w,row_1.w,row_2.w));
		float3 color = lerp(cloud_1_color.xyz,cloud_0_color.xyz,dot(direction,s_light_direction) * 0.5f + 0.5f) * cloud_01_scale;
		
		direction = vertex.xyz * s_depth_range.w;
		float distance = length(direction);
		
		OUT.texcoord_0 = texcoord.xy;
		
		OUT.texcoord_1 = direction;
		
		float ray_density = s_scattering_ray_beta.w;
		float mie_density = s_scattering_mie_beta.w;
		
		float2 falloff = s_scattering_falloff.xy * (dot(direction,s_scattering_up_direction) + s_scattering_falloff.z);
		if(abs(falloff.x) > 0.01f) ray_density *= (1.0f - exp2(-falloff.x)) / falloff.x;
		if(abs(falloff.y) > 0.01f) mie_density *= (1.0f - exp2(-falloff.y)) / falloff.y;
		
		float scattering_distance = pow(distance,s_scattering_power);
		float3 scattering = exp2(-(s_scattering_ray_beta.xyz * ray_density + s_scattering_mie_beta.xyz * mie_density) * scattering_distance);
		
		float angle = dot(direction,s_scattering_light_direction) / distance;
		float ray_phase = 1.0f + angle * angle * s_scattering_ray_dash.w;
		float mie_greenstein = rsqrt(s_scattering_greenstein.y - s_scattering_greenstein.z * angle);
		float mie_phase = min(s_scattering_greenstein.x * mie_greenstein,s_scattering_mie_dash.w * scattering_distance);
		float3 inscattering = s_scattering_ray_dash.xyz * ray_phase + s_scattering_mie_dash.xyz * mie_phase;
		
		float fade = saturate(length(position) / max(width,height));
		
		OUT.texcoord_2.xyz = scattering * color;
		OUT.texcoord_2.w = saturate(dot(scattering,cloud_scattering)) * saturate(-vertex.z / cloud_distance) * fade;
		OUT.texcoord_3.xyz = inscattering * (1.0f - scattering);
		OUT.texcoord_3.w = 0.0f;
		
	#endif
	
/******************************************************************************\
*
* Direct3D9
*
\******************************************************************************/

#elif DIRECT3D9
	
	#ifndef VERTEX_CLOUD_AMBIENT
		#define VERTEX_CLOUD_AMBIENT
		
		struct VERTEX_OUT {
			float4 position : POSITION;
			float2 texcoord_0 : TEXCOORD0;
			float3 texcoord_1 : TEXCOORD1;
			float4 texcoord_2 : TEXCOORD2;
			float4 texcoord_3 : TEXCOORD3;
			#ifdef VOLUME
				float4 texcoord_7 : TEXCOORD7;
			#endif
		};
		
		float4 cloud_0_color;
		float4 cloud_1_color;
		float cloud_01_scale;
		float cloud_power;
		float cloud_scattering;
		float cloud_distance;
		
	#else
		
		OUT.position = getPosition(vertex);
		
		float3 direction = normalize(vertex.xyz - float3(row_0.w,row_1.w,row_2.w));
		float3 color = lerp(cloud_1_color.xyz,cloud_0_color.xyz,dot(direction,s_light_direction) * 0.5f + 0.5f) * cloud_01_scale;
		
		direction = vertex.xyz * s_depth_range.w;
		float distance = length(direction);
		
		OUT.texcoord_0 = texcoord.xy;
		
		OUT.texcoord_1 = direction;
		
		float ray_density = s_scattering_ray_beta.w;
		float mie_density = s_scattering_mie_beta.w;
		
		float2 falloff = s_scattering_falloff.xy * (dot(direction,s_scattering_up_direction) + s_scattering_falloff.z);
		if(abs(falloff.x) > 0.01f) ray_density *= (1.0f - exp2(-falloff.x)) / falloff.x;
		if(abs(falloff.y) > 0.01f) mie_density *= (1.0f - exp2(-falloff.y)) / falloff.y;
		
		float scattering_distance = pow(distance,s_scattering_power);
		float3 scattering = exp2(-(s_scattering_ray_beta.xyz * ray_density + s_scattering_mie_beta.xyz * mie_density) * scattering_distance);
		
		float angle = dot(direction,s_scattering_light_direction) / distance;
		float ray_phase = 1.0f + angle * angle * s_scattering_ray_dash.w;
		float mie_greenstein = rsqrt(s_scattering_greenstein.y - s_scattering_greenstein.z * angle);
		float mie_phase = min(s_scattering_greenstein.x * mie_greenstein,s_scattering_mie_dash.w * scattering_distance);
		float3 inscattering = s_scattering_ray_dash.xyz * ray_phase + s_scattering_mie_dash.xyz * mie_phase;
		
		float fade = saturate(length(position) / max(width,height));
		
		OUT.texcoord_2.xyz = scattering * color;
		OUT.texcoord_2.w = saturate(dot(scattering,cloud_scattering)) * saturate(-vertex.z / cloud_distance) * fade;
		OUT.texcoord_3.xyz = inscattering * (1.0f - scattering);
		OUT.texcoord_3.w = 0.0f;
		
		#ifdef VOLUME
			OUT.texcoord_7 = getProjection(OUT.position);
		#endif
		
	#endif
	
/******************************************************************************\
*
* PlayStation3
*
\******************************************************************************/

#elif PLAYSTATION3
	
	#ifndef VERTEX_CLOUD_AMBIENT
		#define VERTEX_CLOUD_AMBIENT
		
		struct VERTEX_OUT {
			float4 position : POSITION;
			float2 texcoord_0 : TEXCOORD0;
			float3 texcoord_1 : TEXCOORD1;
			float4 texcoord_2 : TEXCOORD2;
			float4 texcoord_3 : TEXCOORD3;
			#ifdef VOLUME
				float4 texcoord_9 : TEXCOORD9;
			#endif
		};
		
		float4 cloud_0_color;
		float4 cloud_1_color;
		float cloud_01_scale;
		float cloud_power;
		float cloud_scattering;
		float cloud_distance;
		
	#else
		
		OUT.position = getPosition(vertex);
		
		float3 direction = normalize(vertex.xyz - float3(row_0.w,row_1.w,row_2.w));
		float3 color = lerp(cloud_1_color.xyz,cloud_0_color.xyz,dot(direction,s_light_direction) * 0.5f + 0.5f) * cloud_01_scale;
		
		direction = vertex.xyz * s_depth_range.w;
		float distance = length(direction);
		
		OUT.texcoord_0 = texcoord.xy;
		
		OUT.texcoord_1 = direction;
		
		float ray_density = s_scattering_ray_beta.w;
		float mie_density = s_scattering_mie_beta.w;
		
		float2 falloff = s_scattering_falloff.xy * (dot(direction,s_scattering_up_direction) + s_scattering_falloff.z);
		if(abs(falloff.x) > 0.01f) ray_density *= (1.0f - exp2(-falloff.x)) / falloff.x;
		if(abs(falloff.y) > 0.01f) mie_density *= (1.0f - exp2(-falloff.y)) / falloff.y;
		
		float scattering_distance = pow(distance,s_scattering_power);
		float3 scattering = exp2(-(s_scattering_ray_beta.xyz * ray_density + s_scattering_mie_beta.xyz * mie_density) * scattering_distance);
		
		float angle = dot(direction,s_scattering_light_direction) / distance;
		float ray_phase = 1.0f + angle * angle * s_scattering_ray_dash.w;
		float mie_greenstein = rsqrt(s_scattering_greenstein.y - s_scattering_greenstein.z * angle);
		float mie_phase = min(s_scattering_greenstein.x * mie_greenstein,s_scattering_mie_dash.w * scattering_distance);
		float3 inscattering = s_scattering_ray_dash.xyz * ray_phase + s_scattering_mie_dash.xyz * mie_phase;
		
		float fade = saturate(length(position) / max(width,height));
		
		OUT.texcoord_2.xyz = scattering * color;
		OUT.texcoord_2.w = saturate(dot(scattering,cloud_scattering)) * saturate(-vertex.z / cloud_distance) * fade;
		OUT.texcoord_3.xyz = inscattering * (1.0f - scattering);
		OUT.texcoord_3.w = 0.0f;
		
		#ifdef VOLUME
			OUT.texcoord_9 = getProjection(OUT.position);
		#endif
		
	#endif
	
#endif
